JSのkeyをVim key codeに変換するscript
{key: 'A', shiftKey: true, ctrlKey: true}などを<C-A>に変換するscript
code:script.js
import {mouseCodes, normalKeys, specialKeys} from './characters.js';
/icons/javascript.icon→/icons/Vim.icon
<は\<になる
\ は\\になる
code:script.js
export function js2vim({key, button, ctrlKey, shiftKey, altKey}) {
let code = '';
// マウスクリックの場合
if (button) {
code = button < 3 ? mouseCodesbutton : 'otherMouse'; // キーボード入力の場合
} else if (key) {
// Processは無視
if (key === 'Process') return undefined;
switch(key) {
// 修飾キーのみの場合は無視
case 'Shift':
case 'Control':
case 'Alt':
return undefined;
default:
if (!(key in specialKeys) && !(key in normalKeys)) {
const json = {key, ctrlKey, shiftKey, altKey};
throw Error(Invalid key name: ${JSON.stringify(json)});
}
code = specialKeyskey ?? normalKeyskey; break;
}
} else {
return undefined;
}
// 修飾キーをつける
// どれか一つのmeta keyしか有効にしない
if (altKey) return <A-${code}>;
if (ctrlKey) return <C-${code}>;
// Shift keyは印字可能キー以外につける
if (shiftKey && !(key in normalKeys)) return <S-${code}>;
return (key in specialKeys) ? <${code}> : code;
}
/icons/Vim.icon→/icons/javascript.icon
code:script.js
const rMouseCodes = reverse(mouseCodes);
const rNormalKeys = reverse(normalKeys);
const rSpecialKeys = reverse(specialKeys);
export function vim2js(keyString) {
const {meta, key} = parse(keyString);
if (key in rMouseCodes) {
const button = rMouseCodeskey; switch (meta) {
case 'A':
return {button, altKey: meta};
case 'S':
return {button, shiftKey: meta};
case 'C':
return {button, ctrlKey: meta};
}
}
const newKey = rNormalKeyskey ?? rNormalKeyskey; if (newKey === undefined) throw Error(Invalid key notation: ${JSON.stringify({notation: keyString, meta, key})});
switch (meta) {
case 'A':
return {key: newKey, altKey: meta};
case 'S':
return {key: newKey, shiftKey: meta};
case 'C':
return {key: newKey, ctrlKey: meta};
}
}
// keyの解析
function parse(keyString) {
if (/^<ASC-(?:>|^>+)>$/.test(keyString)) { return {meta, key};
}
if (/^<^>>$/.test(keyString)) { return {key: keyString.slice(1, -1)};
}
return {key: keyString};
}
function reverse(object) {
return Object.fromEntries(Object.entries(object).map(pair => pair.reverse()));
}
code:characters.js
// <>無しのキー
export const normalKeys = Object.fromEntries(
range('!'.charCodeAt(0), '~'.charCodeAt(0))
.flatMap(code => {
const key = String.fromCodePoint(code);
if (key === '<') return ['\\<'];
if (key === '\\') return '\\', '\\\\';
return key, key;
})
);
// <>ありのキー
export const specialKeys = {
Backspace: 'BS',
Enter: 'CR',
Delete: 'Del',
Escape: 'Esc',
' ': 'Space',
ArrowLeft: 'Left',
ArrowUp: 'Up',
ArrowRight: 'Right',
ArrowDown: 'Down',
...Object.fromEntries([
'Tab', 'PageUp', 'PageDown', 'End', 'Home',
...range(1, 12).map(i => F${i + 1}),
};
export const keyboardCodes = {...specialKeys, ...normalKeys};
export const mouseCodes = {
0: 'LeftMouse',
1: 'MiddleMouse',
2: 'RightMouse',
};
test code
code:js
import('/api/code/programming-notes/JSのkeyをVim_key_codeに変換するscript/test1.js');
code:test1.js
import {js2vim} from './script.js';
const chars = '!"#$%&\'()~=~|QWERTYUIOP`{ASDFGHJKL+*}ZXCVBNM<>?_qwertyuiop@asdfghjkl;:zxcvbnm,./\\-^'; console.log(chars.split('').map(key => {
const code = js2vim({key, shiftKey: true});
return {code, judge: code === key};
}));
console.log(chars.split('').map(key => {
const code = js2vim({key, altKey: true, ctrlKey: true});
return {code, judge: code === <A-${key}>};
}));
console.log(chars.split('').map(key => {
const code = js2vim({key, ctrlKey: true});
return {code, judge: code === <C-${key}>};
}));
JavaScript.icon